/**
 * Bamboo Software Organization
 * Java open source software.  
 */
package org.bamboo.easyejb.reflect;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Reflection utils. Get right method just by class,method name and args
 * @author Ramond KK He, raymond.kk.he@gmail.com 
 * @version 1.0 
 * 2008-11-27  
 */
public class ReflectUtils {
	public static final Map primitiveTypes = new HashMap();
	static {
		//8 primitives
		primitiveTypes.put( java.lang.Character.class,"char");
		primitiveTypes.put( java.lang.Byte.class,"byte");
		primitiveTypes.put( java.lang.Short.class,"short");
		primitiveTypes.put( java.lang.Integer.class,"int");
		primitiveTypes.put( java.lang.Long.class,"long");
		primitiveTypes.put( java.lang.Float.class,"float");
		primitiveTypes.put(java.lang.Double.class,"double" );
		primitiveTypes.put( java.lang.Boolean.class,"boolean");
		;
	}
	
	/**
	 * get right method by class,methodname and args. paramdef Class[] not required any longer
	 * @param clazz
	 * @param methodName
	 * @param args
	 * @return
	 * @throws NoSuchMethodException
	 */
	public static  Method getRightMethodByArgs(Class clazz, String methodName, Object[] args) throws NoSuchMethodException {
		//zero args method
		if(args == null) {
			Method method = clazz.getMethod(methodName, null);
			return method;
		}
		
		Method[] methods = clazz.getMethods();
		
		List targetMethods0 = new ArrayList(1);
		List targetMethods = new ArrayList(1);
		for (int i = 0; i < methods.length; i++) {
			//if name match
			if(methods[i].getName().equalsIgnoreCase(methodName) ) {
				targetMethods0.add(methods[i]);			}
		}
		if(targetMethods0.size() == 0)
			throw new NoSuchMethodException("Not such method:" + methodName);
		
		for (int i = 0; i < targetMethods0.size(); i++) {
			//if consistent in param length
			Method method = (Method)targetMethods0.get(i);
			if(method.getParameterTypes().length == args.length) {
				targetMethods.add(method);
			}
		}
		if(targetMethods.size() == 0)
			throw new NoSuchMethodException("No proper method found! Wrong number args. " + methodName +", input args len:" + args.length);
		
		
//		if(targetMethods.size() == 1)
//			return (Method)targetMethods.get(0);
//		else //both name and param length match, but param class not match
//		{
			for (int i = 0; i < targetMethods.size(); i++) {
				
				Method mmm = (Method)targetMethods.get(i);
				Class[] paramDef = mmm.getParameterTypes();
				int matchCount = 0;
				for (int k = 0; k < paramDef.length; k++) {
					if(args[k] == null 
							|| paramDef[k].isAssignableFrom(args[k].getClass())
							|| (paramDef[k].isPrimitive() && primitiveTypes.get(args[k].getClass()).equals(paramDef[k].toString()))) {
						matchCount++;
					}
					//else, incompatible, don't matchCount++
				}
				//found match
				if(matchCount == paramDef.length)
					return mmm; //find the right method
			}
//		}
		//no method match
		throw new NoSuchMethodException("No proper method found! Arguments type incompatible! " + array2String(args));
	}
	
	public static String array2String(Object[] args) {
		StringBuffer buffer = new StringBuffer(64);
		buffer.append("<Array,Len:").append(args.length).append(">[");
		for (int i = 0; i < args.length; i++) {
			buffer.append(args[i]);
			if(i< args.length-1)
				buffer.append(",");
		}
		buffer.append("]");
		return buffer.toString();
	}
}
